');
} else {
$(datatable.tableHead).find('.' + pfx + 'datatable__toggle-detail').find('span').css('width', '21px');
}
});
},
/**
* todo; implement hover column
*/
hoverColumn: function() {
$(datatable.tableBody).on('mouseenter', '.' + pfx + 'datatable__cell', function() {
var colIdx = $(Plugin.cell(this).nodes()).index();
$(Plugin.cells().nodes()).removeClass(pfx + 'datatable__cell--hover');
$(Plugin.column(colIdx).nodes()).addClass(pfx + 'datatable__cell--hover');
});
},
/**
* To enable auto columns features for remote data source
*/
setAutoColumns: function() {
if (Plugin.getOption('data.autoColumns')) {
$.each(datatable.dataSet[0], function(k, v) {
var found = $.grep(options.columns, function(n, i) {
return k === n.field;
});
if (found.length === 0) {
options.columns.push({field: k, title: k});
}
});
$(datatable.tableHead).find('.' + pfx + 'datatable__row').remove();
Plugin.setHeadTitle();
if (Plugin.getOption('layout.footer')) {
$(datatable.tableFoot).find('.' + pfx + 'datatable__row').remove();
Plugin.setHeadTitle(datatable.tableFoot);
}
}
},
/********************
** HELPERS
********************/
/**
* Check if table is a locked colums table
*/
isLocked: function() {
return util.hasClass(datatable.wrap[0], pfx + 'datatable--lock') || false;
},
/**
* Get total extra space of an element for width calculation, including
* padding, margin, border
* @param element
* @returns {number}
*/
getExtraSpace: function(element) {
var padding = parseInt($(element).css('paddingRight')) +
parseInt($(element).css('paddingLeft'));
var margin = parseInt($(element).css('marginRight')) +
parseInt($(element).css('marginLeft'));
var border = Math.ceil(
$(element).css('border-right-width').replace('px', ''));
return padding + margin + border;
},
/**
* Insert data of array into {{ }} template placeholder
* @param template
* @param data
* @returns {*}
*/
dataPlaceholder: function(template, data) {
var result = template;
$.each(data, function(key, val) {
result = result.replace('{{' + key + '}}', val);
});
return result;
},
/**
* Get table unique ID
* Note: table unique change each time refreshed
* @param suffix
* @returns {*}
*/
getTableId: function(suffix) {
if (typeof suffix === 'undefined') suffix = '';
var id = $(datatable).attr('id');
if (typeof id === 'undefined') {
id = $(datatable).attr('class').split(' ')[0];
}
return id + suffix;
},
/**
* Get table prefix with depth number
*/
getTablePrefix: function(suffix) {
if (typeof suffix !== 'undefined') suffix = '-' + suffix;
return Plugin.getTableId() + '-' + Plugin.getDepth() + suffix;
},
/**
* Get current table depth of sub table
* @returns {number}
*/
getDepth: function() {
var depth = 0;
var table = datatable.table;
do {
table = $(table).parents('.' + pfx + 'datatable__table');
depth++;
} while ($(table).length > 0);
return depth;
},
/**
* Keep state item
* @param key
* @param value
*/
stateKeep: function(key, value) {
key = Plugin.getTablePrefix(key);
if (Plugin.getOption('data.saveState') === false) return;
if (Plugin.getOption('data.saveState.webstorage') && localStorage) {
localStorage.setItem(key, JSON.stringify(value));
}
if (Plugin.getOption('data.saveState.cookie')) {
Cookies.set(key, JSON.stringify(value));
}
},
/**
* Get state item
* @param key
* @param defValue
*/
stateGet: function(key, defValue) {
key = Plugin.getTablePrefix(key);
if (Plugin.getOption('data.saveState') === false) return;
var value = null;
if (Plugin.getOption('data.saveState.webstorage') && localStorage) {
value = localStorage.getItem(key);
} else {
value = Cookies.get(key);
}
if (typeof value !== 'undefined' && value !== null) {
return JSON.parse(value);
}
},
/**
* Update data in state without clear existing
* @param key
* @param value
*/
stateUpdate: function(key, value) {
var ori = Plugin.stateGet(key);
if (typeof ori === 'undefined' || ori === null) ori = {};
Plugin.stateKeep(key, $.extend({}, ori, value));
},
/**
* Remove state item
* @param key
*/
stateRemove: function(key) {
key = Plugin.getTablePrefix(key);
if (localStorage) {
localStorage.removeItem(key);
}
Cookies.remove(key);
},
/**
* Get total columns.
*/
getTotalColumns: function(tablePart) {
if (typeof tablePart === 'undefined') tablePart = datatable.tableBody;
return $(tablePart).find('.' + pfx + 'datatable__row').first().find('.' + pfx + 'datatable__cell').length;
},
/**
* Get table row. Useful to get row when current table is in lock mode.
* Can be used for both lock and normal table mode.
* By default, returning result will be in a list of
.
* @param tablePart
* @param row 1-based index
* @param tdOnly Optional. Default true
* @returns {*}
*/
getOneRow: function(tablePart, row, tdOnly) {
if (typeof tdOnly === 'undefined') tdOnly = true;
// get list of
var result = $(tablePart).find('.' + pfx + 'datatable__row:not(.' + pfx + 'datatable__row-detail):nth-child(' + row + ')');
if (tdOnly) {
// get list of
or
result = result.find('.' + pfx + 'datatable__cell');
}
return result;
},
/**
* Check if element has vertical overflow
* @param element
* @returns {boolean}
*/
hasOverflowY: function(element) {
var children = $(element).find('.' + pfx + 'datatable__row');
var maxHeight = 0;
if (children.length > 0) {
$(children).each(function(tdi, td) {
maxHeight += Math.floor($(td).innerHeight());
});
return maxHeight > $(element).innerHeight();
}
return false;
},
/**
* Sort table row at HTML level by column index.
* todo; Not in use.
* @param header Header sort clicked
* @param sort asc|desc. Optional. Default asc
* @param int Boolean. Optional. Comparison value parse to integer.
* Default false
*/
sortColumn: function(header, sort, int) {
if (typeof sort === 'undefined') sort = 'asc'; // desc
if (typeof int === 'undefined') int = false;
var column = $(header).index();
var rows = $(datatable.tableBody).find('.' + pfx + 'datatable__row');
var hIndex = $(header).closest('.' + pfx + 'datatable__lock').index();
if (hIndex !== -1) {
rows = $(datatable.tableBody).find('.' + pfx + 'datatable__lock:nth-child(' + (hIndex + 1) + ')').find('.' + pfx + 'datatable__row');
}
var container = $(rows).parent();
$(rows).sort(function(a, b) {
var tda = $(a).find('td:nth-child(' + column + ')').text();
var tdb = $(b).find('td:nth-child(' + column + ')').text();
if (int) {
// useful for integer type sorting
tda = parseInt(tda);
tdb = parseInt(tdb);
}
if (sort === 'asc') {
return tda > tdb ? 1 : tda < tdb ? -1 : 0;
} else {
return tda < tdb ? 1 : tda > tdb ? -1 : 0;
}
}).appendTo(container);
},
/**
* Perform sort remote and local
*/
sorting: function() {
var sortObj = {
init: function() {
if (options.sortable) {
$(datatable.tableHead).
find('.' + pfx + 'datatable__cell:not(.' + pfx + 'datatable__cell--check)').
addClass(pfx + 'datatable__cell--sort').
off('click').
on('click', sortObj.sortClick);
// first init
sortObj.setIcon();
}
},
setIcon: function() {
var meta = Plugin.getDataSourceParam('sort');
if ($.isEmptyObject(meta)) return;
// sort icon beside column header
var td = $(datatable.tableHead).find('.' + pfx + 'datatable__cell[data-field="' + meta.field + '"]').attr('data-sort', meta.sort);
var sorting = $(td).find('span');
var icon = $(sorting).find('i');
var icons = Plugin.getOption('layout.icons.sort');
// update sort icon; desc & asc
if ($(icon).length > 0) {
$(icon).removeAttr('class').addClass(icons[meta.sort]);
} else {
$(sorting).append($('').addClass(icons[meta.sort]));
}
},
sortClick: function(e) {
var meta = Plugin.getDataSourceParam('sort');
var field = $(this).data('field');
var column = Plugin.getColumnByField(field);
// sort is disabled for this column
if (typeof column.sortable !== 'undefined' &&
column.sortable === false) return;
$(datatable.tableHead).find('.' + pfx + 'datatable__cell > span > i').remove();
if (options.sortable) {
Plugin.spinnerCallback(true);
var sort = 'desc';
if (Plugin.getObject('field', meta) === field) {
sort = Plugin.getObject('sort', meta);
}
// toggle sort
sort = typeof sort === 'undefined' || sort === 'desc'
? 'asc'
: 'desc';
// update field and sort params
meta = {field: field, sort: sort};
Plugin.setDataSourceParam('sort', meta);
sortObj.setIcon();
setTimeout(function() {
Plugin.dataRender('sort');
$(datatable).trigger(pfx + 'datatable--on-sort', meta);
}, 300);
}
},
};
sortObj.init();
},
/**
* Update JSON data list linked with sort, filter and pagination.
* Call this method, before using dataSet variable.
* @returns {*|null}
*/
localDataUpdate: function() {
// todo; fix twice execution
var params = Plugin.getDataSourceParam();
if (typeof datatable.originalDataSet === 'undefined') {
datatable.originalDataSet = datatable.dataSet;
}
var field = Plugin.getObject('sort.field', params);
var sort = Plugin.getObject('sort.sort', params);
var column = Plugin.getColumnByField(field);
if (typeof column !== 'undefined' && Plugin.getOption('data.serverSorting') !== true) {
if (typeof column.sortCallback === 'function') {
datatable.dataSet = column.sortCallback(datatable.originalDataSet, sort, column);
} else {
datatable.dataSet = Plugin.sortCallback(datatable.originalDataSet, sort, column);
}
} else {
datatable.dataSet = datatable.originalDataSet;
}
// if server filter enable, don't pass local filter
if (typeof params.query === 'object' && !Plugin.getOption('data.serverFiltering')) {
params.query = params.query || {};
var nestedSearch = function(obj) {
for (var field in obj) {
if (!obj.hasOwnProperty(field)) continue;
if (typeof obj[field] === 'string') {
if (obj[field].toLowerCase() == search || obj[field].toLowerCase().indexOf(search) !== -1) {
return true;
}
}
else if (typeof obj[field] === 'number') {
if (obj[field] === search) {
return true;
}
}
else if (typeof obj[field] === 'object') {
return nestedSearch(obj[field]);
}
}
return false;
};
var search = $(Plugin.getOption('search.input')).val();
if (typeof search !== 'undefined' && search !== '') {
search = search.toLowerCase();
datatable.dataSet = $.grep(datatable.dataSet, nestedSearch);
// remove generalSearch as we don't need this for next columns filter
delete params.query[Plugin.getGeneralSearchKey()];
}
// remove empty element from array
$.each(params.query, function(k, v) {
if (v === '') {
delete params.query[k];
}
});
// filter array by query
datatable.dataSet = Plugin.filterArray(datatable.dataSet, params.query);
// reset array index
datatable.dataSet = datatable.dataSet.filter(function() {
return true;
});
}
return datatable.dataSet;
},
/**
* Utility helper to filter array by object pair of {key:value}
* @param list
* @param args
* @param operator
* @returns {*}
*/
filterArray: function(list, args, operator) {
if (typeof list !== 'object') {
return [];
}
if (typeof operator === 'undefined') operator = 'AND';
if (typeof args !== 'object') {
return list;
}
operator = operator.toUpperCase();
if ($.inArray(operator, ['AND', 'OR', 'NOT']) === -1) {
return [];
}
var count = Object.keys(args).length;
var filtered = [];
$.each(list, function(key, obj) {
var to_match = obj;
var matched = 0;
$.each(args, function(m_key, m_value) {
m_value = m_value instanceof Array ? m_value : [m_value];
if (to_match.hasOwnProperty(m_key)) {
var lhs = to_match[m_key].toString().toLowerCase();
m_value.forEach(function(item, index) {
if (item.toString().toLowerCase() == lhs || lhs.indexOf(item.toString().toLowerCase()) !== -1) {
matched++;
}
});
}
});
if (('AND' == operator && matched == count) ||
('OR' == operator && matched > 0) ||
('NOT' == operator && 0 == matched)) {
filtered[key] = obj;
}
});
list = filtered;
return list;
},
/**
* Reset lock column scroll to 0 when resize
*/
resetScroll: function() {
if (typeof options.detail === 'undefined' && Plugin.getDepth() === 1) {
$(datatable.table).find('.' + pfx + 'datatable__row').css('left', 0);
$(datatable.table).find('.' + pfx + 'datatable__lock').css('top', 0);
$(datatable.tableBody).scrollTop(0);
}
},
/**
* Get column options by field
* @param field
* @returns {boolean}
*/
getColumnByField: function(field) {
if (typeof field === 'undefined') return;
var result;
$.each(options.columns, function(i, column) {
if (field === column.field) {
result = column;
return false;
}
});
return result;
},
/**
* Get default sort column
*/
getDefaultSortColumn: function() {
var result;
$.each(options.columns, function(i, column) {
if (typeof column.sortable !== 'undefined'
&& $.inArray(column.sortable, ['asc', 'desc']) !== -1) {
result = {sort: column.sortable, field: column.field};
return false;
}
});
return result;
},
/**
* Helper to get element dimensions, when the element is hidden
* @param element
* @param includeMargin
* @returns {{width: number, height: number, innerWidth: number,
* innerHeight: number, outerWidth: number, outerHeight: number}}
*/
getHiddenDimensions: function(element, includeMargin) {
var props = {
position: 'absolute',
visibility: 'hidden',
display: 'block',
},
dim = {
width: 0,
height: 0,
innerWidth: 0,
innerHeight: 0,
outerWidth: 0,
outerHeight: 0,
},
hiddenParents = $(element).parents().addBack().not(':visible');
includeMargin = (typeof includeMargin === 'boolean')
? includeMargin
: false;
var oldProps = [];
hiddenParents.each(function() {
var old = {};
for (var name in props) {
old[name] = this.style[name];
this.style[name] = props[name];
}
oldProps.push(old);
});
dim.width = $(element).width();
dim.outerWidth = $(element).outerWidth(includeMargin);
dim.innerWidth = $(element).innerWidth();
dim.height = $(element).height();
dim.innerHeight = $(element).innerHeight();
dim.outerHeight = $(element).outerHeight(includeMargin);
hiddenParents.each(function(i) {
var old = oldProps[i];
for (var name in props) {
this.style[name] = old[name];
}
});
return dim;
},
getGeneralSearchKey: function() {
var searchInput = $(Plugin.getOption('search.input'));
return $(searchInput).prop('name') || $(searchInput).prop('id');
},
/**
* Get value by dot notation path string and to prevent undefined errors
* @param path String Dot notation path in string
* @param object Object to iterate
* @returns {*}
*/
getObject: function(path, object) {
return path.split('.').reduce(function(obj, i) {
return obj !== null && typeof obj[i] !== 'undefined' ? obj[i] : null;
}, object);
},
/**
* Extend object
* @param obj
* @param path
* @param value
* @returns {*}
*/
extendObj: function(obj, path, value) {
var levels = path.split('.'),
i = 0;
function createLevel(child) {
var name = levels[i++];
if (typeof child[name] !== 'undefined' && child[name] !== null) {
if (typeof child[name] !== 'object' &&
typeof child[name] !== 'function') {
child[name] = {};
}
} else {
child[name] = {};
}
if (i === levels.length) {
child[name] = value;
} else {
createLevel(child[name]);
}
}
createLevel(obj);
return obj;
},
rowEvenOdd: function() {
// row even class
$(datatable.tableBody).find('.' + pfx + 'datatable__row').removeClass(pfx + 'datatable__row--even');
if ($(datatable.wrap).hasClass(pfx + 'datatable--subtable')) {
$(datatable.tableBody).find('.' + pfx + 'datatable__row:not(.' + pfx + 'datatable__row-detail):even').addClass(pfx + 'datatable__row--even');
} else {
$(datatable.tableBody).find('.' + pfx + 'datatable__row:nth-child(even)').addClass(pfx + 'datatable__row--even');
}
},
/********************
** PUBLIC API METHODS
********************/
// delay timer
timer: 0,
/**
* Redraw datatable by recalculating its DOM elements, etc.
* @returns {jQuery}
*/
redraw: function() {
Plugin.adjustCellsWidth.call();
if (Plugin.isLocked()) {
// fix hiding cell width issue
Plugin.scrollbar();
Plugin.resetScroll();
Plugin.adjustCellsHeight.call();
}
Plugin.adjustLockContainer.call();
Plugin.initHeight.call();
return datatable;
},
/**
* Shortcode to reload
* @returns {jQuery}
*/
load: function() {
Plugin.reload();
return datatable;
},
/**
* Datasource reload
* @returns {jQuery}
*/
reload: function() {
var delay = (function() {
return function(callback, ms) {
clearTimeout(Plugin.timer);
Plugin.timer = setTimeout(callback, ms);
};
})();
delay(function() {
// local only. remote pagination will skip this block
if (!options.data.serverFiltering) {
Plugin.localDataUpdate();
}
Plugin.dataRender();
$(datatable).trigger(pfx + 'datatable--on-reloaded');
}, Plugin.getOption('search.delay'));
return datatable;
},
/**
* Get record by record ID
* @param id
* @returns {jQuery}
*/
getRecord: function(id) {
if (typeof datatable.tableBody === 'undefined') datatable.tableBody = $(datatable.table).children('tbody');
$(datatable.tableBody).find('.' + pfx + 'datatable__cell:first-child').each(function(i, cell) {
if (id == $(cell).text()) {
var rowNumber = $(cell).closest('.' + pfx + 'datatable__row').index() + 1;
datatable.API.record = datatable.API.value = Plugin.getOneRow(datatable.tableBody, rowNumber);
return datatable;
}
});
return datatable;
},
/**
* @deprecated in v5.0.6
* Get column of current record ID
* @param columnName
* @returns {jQuery}
*/
getColumn: function(columnName) {
Plugin.setSelectedRecords();
datatable.API.value = $(datatable.API.record).find('[data-field="' + columnName + '"]');
return datatable;
},
/**
* Destroy datatable to original DOM state before datatable was
* initialized
* @returns {jQuery}
*/
destroy: function() {
$(datatable).parent().find('.' + pfx + 'datatable__pager').remove();
var initialDatatable = $(datatable.initialDatatable).addClass(pfx + 'datatable--destroyed').show();
$(datatable).replaceWith(initialDatatable);
datatable = initialDatatable;
$(datatable).trigger(pfx + 'datatable--on-destroy');
Plugin.isInit = false;
initialDatatable = null;
return initialDatatable;
},
/**
* Sort by column field
* @param field
* @param sort
*/
sort: function(field, sort) {
// toggle sort
sort = typeof sort === 'undefined' ? 'asc' : sort;
Plugin.spinnerCallback(true);
// update field and sort params
var meta = {field: field, sort: sort};
Plugin.setDataSourceParam('sort', meta);
setTimeout(function() {
Plugin.dataRender('sort');
$(datatable).trigger(pfx + 'datatable--on-sort', meta);
$(datatable.tableHead).find('.' + pfx + 'datatable__cell > span > i').remove();
}, 300);
return datatable;
},
/**
* @deprecated in v5.0.6
* Get current selected column value
* @returns {jQuery}
*/
getValue: function() {
return $(datatable.API.value).text();
},
/**
* Set checkbox active
* @param cell JQuery selector or checkbox ID
*/
setActive: function(cell) {
if (typeof cell === 'string') {
// set by checkbox id
cell = $(datatable.tableBody).find('.' + pfx + 'checkbox--single > [type="checkbox"][value="' + cell + '"]');
}
$(cell).prop('checked', true);
// normal table
var row = $(cell).closest('.' + pfx + 'datatable__row').addClass(pfx + 'datatable__row--active');
var index = $(row).index() + 1;
// lock table
$(row).closest('.' + pfx + 'datatable__lock').parent().find('.' + pfx + 'datatable__row:nth-child(' + index + ')').addClass(pfx + 'datatable__row--active');
var ids = [];
$(row).each(function(i, td) {
var id = $(td).find('.' + pfx + 'checkbox--single:not(.' + pfx + 'checkbox--all) > [type="checkbox"]').val();
if (typeof id !== 'undefined') {
ids.push(id);
}
});
$(datatable).trigger(pfx + 'datatable--on-check', [ids]);
},
/**
* Set checkbox inactive
* @param cell JQuery selector or checkbox ID
*/
setInactive: function(cell) {
if (typeof cell === 'string') {
// set by checkbox id
cell = $(datatable.tableBody).find('.' + pfx + 'checkbox--single > [type="checkbox"][value="' + cell + '"]');
}
$(cell).prop('checked', false);
// normal table
var row = $(cell).closest('.' + pfx + 'datatable__row').removeClass(pfx + 'datatable__row--active');
var index = $(row).index() + 1;
// lock table
$(row).closest('.' + pfx + 'datatable__lock').parent().find('.' + pfx + 'datatable__row:nth-child(' + index + ')').removeClass(pfx + 'datatable__row--active');
var ids = [];
$(row).each(function(i, td) {
var id = $(td).find('.' + pfx + 'checkbox--single:not(.' + pfx + 'checkbox--all) > [type="checkbox"]').val();
if (typeof id !== 'undefined') {
ids.push(id);
}
});
$(datatable).trigger(pfx + 'datatable--on-uncheck', [ids]);
},
/**
* Set all checkboxes active or inactive
* @param active
*/
setActiveAll: function(active) {
// todo; check if child table also will set active?
var checkboxes = $(datatable.table).find('> tbody, > thead').find('> tr:not(.' + pfx + 'datatable__row-subtable)').find('.' + pfx + 'datatable__cell--check [type="checkbox"]');
if (active) {
Plugin.setActive(checkboxes);
} else {
Plugin.setInactive(checkboxes);
}
},
/**
* @deprecated in v5.0.6
* Get selected rows which are active
* @returns {jQuery}
*/
setSelectedRecords: function() {
datatable.API.record = $(datatable.tableBody).find('.' + pfx + 'datatable__row--active');
return datatable;
},
/**
* Get selected records
* @returns {null}
*/
getSelectedRecords: function() {
// support old method
Plugin.setSelectedRecords();
datatable.API.record = datatable.rows('.' + pfx + 'datatable__row--active').nodes();
return datatable.API.record;
},
/**
* Get options by dots notation path
* @param path String Dot notation path in string
* @returns {*}
*/
getOption: function(path) {
return Plugin.getObject(path, options);
},
/**
* Set global options nodes by dots notation path
* @param path
* @param object
*/
setOption: function(path, object) {
options = Plugin.extendObj(options, path, object);
},
/**
* Search filter for local & remote
* @param value
* @param columns. Optional list of columns to be filtered.
*/
search: function(value, columns) {
if (typeof columns !== 'undefined') columns = $.makeArray(columns);
var delay = (function() {
return function(callback, ms) {
clearTimeout(Plugin.timer);
Plugin.timer = setTimeout(callback, ms);
};
})();
delay(function() {
// get query parameters
var query = Plugin.getDataSourceQuery();
// search not by columns
if (typeof columns === 'undefined' && typeof value !== 'undefined') {
var key = Plugin.getGeneralSearchKey();
query[key] = value;
}
// search by columns, support multiple columns
if (typeof columns === 'object') {
$.each(columns, function(k, column) {
query[column] = value;
});
// remove empty element from arrays
$.each(query, function(k, v) {
if (v === '' || $.isEmptyObject(v)) {
delete query[k];
}
});
}
Plugin.setDataSourceQuery(query);
// local filter only. remote pagination will skip this block
if (!options.data.serverFiltering) {
Plugin.localDataUpdate();
}
Plugin.dataRender('search');
}, Plugin.getOption('search.delay'));
},
/**
* Set datasource params extract
* @param param
* @param value
*/
setDataSourceParam: function(param, value) {
datatable.API.params = $.extend({}, {
pagination: {page: 1, perpage: Plugin.getOption('data.pageSize')},
sort: Plugin.getDefaultSortColumn(),
query: {},
}, datatable.API.params, Plugin.stateGet(Plugin.stateId));
datatable.API.params = Plugin.extendObj(datatable.API.params, param, value);
Plugin.stateKeep(Plugin.stateId, datatable.API.params);
},
/**
* Get datasource params
* @param param
*/
getDataSourceParam: function(param) {
datatable.API.params = $.extend({}, {
pagination: {page: 1, perpage: Plugin.getOption('data.pageSize')},
sort: Plugin.getDefaultSortColumn(),
query: {},
}, datatable.API.params, Plugin.stateGet(Plugin.stateId));
if (typeof param === 'string') {
return Plugin.getObject(param, datatable.API.params);
}
return datatable.API.params;
},
/**
* Shortcode to datatable.getDataSourceParam('query');
* @returns {*}
*/
getDataSourceQuery: function() {
return Plugin.getDataSourceParam('query') || {};
},
/**
* Shortcode to datatable.setDataSourceParam('query', query);
* @param query
*/
setDataSourceQuery: function(query) {
Plugin.setDataSourceParam('query', query);
},
/**
* Get current page number
* @returns {number}
*/
getCurrentPage: function() {
return $(datatable.table).
siblings('.' + pfx + 'datatable__pager').
last().
find('.' + pfx + 'datatable__pager-nav').
find('.' + pfx + 'datatable__pager-link.' + pfx + 'datatable__pager-link--active').
data('page') || 1;
},
/**
* Get selected dropdown page size
* @returns {*|number}
*/
getPageSize: function() {
return $(datatable.table).siblings('.' + pfx + 'datatable__pager').last().find('select.' + pfx + 'datatable__pager-size').val() || 10;
},
/**
* Get total rows
*/
getTotalRows: function() {
return datatable.API.params.pagination.total;
},
/**
* Get full dataset in grid
* @returns {*|null|Array}
*/
getDataSet: function() {
return datatable.originalDataSet;
},
/**
* @deprecated in v5.0.6
* Hide column by column's field name
* @param fieldName
*/
hideColumn: function(fieldName) {
// add hide option for this column
$.map(options.columns, function(column) {
if (fieldName === column.field) {
column.responsive = {hidden: 'xl'};
}
return column;
});
// hide current displayed column
var tds = $.grep($(datatable.table).find('.' + pfx + 'datatable__cell'), function(n, i) {
return fieldName === $(n).data('field');
});
$(tds).hide();
},
/**
* @deprecated in v5.0.6
* Show column by column's field name
* @param fieldName
*/
showColumn: function(fieldName) {
// add hide option for this column
$.map(options.columns, function(column) {
if (fieldName === column.field) {
delete column.responsive;
}
return column;
});
// hide current displayed column
var tds = $.grep($(datatable.table).find('.' + pfx + 'datatable__cell'), function(n, i) {
return fieldName === $(n).data('field');
});
$(tds).show();
},
nodeTr: [],
nodeTd: [],
nodeCols: [],
recentNode: [],
table: function() {
return datatable.table;
},
/**
* Select a single row from the table
* @param selector
* @returns {jQuery}
*/
row: function(selector) {
Plugin.rows(selector);
Plugin.nodeTr = Plugin.recentNode = $(Plugin.nodeTr).first();
return datatable;
},
/**
* Select multiple rows from the table
* @param selector
* @returns {jQuery}
*/
rows: function(selector) {
Plugin.nodeTr = Plugin.recentNode = $(datatable.tableBody).find(selector).filter('.' + pfx + 'datatable__row');
return datatable;
},
/**
* Select a single column from the table
* @param index zero-based index
* @returns {jQuery}
*/
column: function(index) {
Plugin.nodeCols = Plugin.recentNode = $(datatable.tableBody).find('.' + pfx + 'datatable__cell:nth-child(' + (index + 1) + ')');
return datatable;
},
/**
* Select multiple columns from the table
* @param selector
* @returns {jQuery}
*/
columns: function(selector) {
var context = datatable.table;
if (Plugin.nodeTr === Plugin.recentNode) {
context = Plugin.nodeTr;
}
var columns = $(context).find('.' + pfx + 'datatable__cell[data-field="' + selector + '"]');
if (columns.length > 0) {
Plugin.nodeCols = Plugin.recentNode = columns;
} else {
Plugin.nodeCols = Plugin.recentNode = $(context).find(selector).filter('.' + pfx + 'datatable__cell');
}
return datatable;
},
cell: function(selector) {
Plugin.cells(selector);
Plugin.nodeTd = Plugin.recentNode = $(Plugin.nodeTd).first();
return datatable;
},
cells: function(selector) {
var cells = $(datatable.tableBody).find('.' + pfx + 'datatable__cell');
if (typeof selector !== 'undefined') {
cells = $(cells).filter(selector);
}
Plugin.nodeTd = Plugin.recentNode = cells;
return datatable;
},
/**
* Delete the selected row from the table
* @returns {jQuery}
*/
remove: function() {
if ($(Plugin.nodeTr.length) && Plugin.nodeTr === Plugin.recentNode) {
$(Plugin.nodeTr).remove();
}
Plugin.layoutUpdate();
return datatable;
},
/**
* Show or hide the columns or rows
*/
visible: function(bool) {
if ($(Plugin.recentNode.length)) {
var locked = Plugin.lockEnabledColumns();
if (Plugin.recentNode === Plugin.nodeCols) {
var index = Plugin.recentNode.index();
if (Plugin.isLocked()) {
var scrollColumns = $(Plugin.recentNode).closest('.' + pfx + 'datatable__lock--scroll').length;
if (scrollColumns) {
// is at center of scrollable area
index += locked.left.length + 1;
} else if ($(Plugin.recentNode).closest('.' + pfx + 'datatable__lock--right').length) {
// is at the right locked table
index += locked.left.length + scrollColumns + 1;
}
}
}
if (bool) {
if (Plugin.recentNode === Plugin.nodeCols) {
delete options.columns[index].responsive;
}
$(Plugin.recentNode).show();
} else {
if (Plugin.recentNode === Plugin.nodeCols) {
Plugin.setOption('columns.' + index + '.responsive', {hidden: 'xl'});
}
$(Plugin.recentNode).hide();
}
Plugin.redraw();
}
},
/**
* Get the the DOM element for the selected rows or columns
* @returns {Array}
*/
nodes: function() {
return Plugin.recentNode;
},
/**
* will be implemented soon
* @returns {jQuery}
*/
dataset: function() {
return datatable;
},
};
/**
* Public API methods can be used directly by datatable
*/
$.each(Plugin, function(funcName, func) {
datatable[funcName] = func;
});
// initialize main datatable plugin
if (typeof options !== 'undefined') {
if (typeof options === 'string') {
var method = options;
datatable = $(this).data(pluginName);
if (typeof datatable !== 'undefined') {
options = datatable.options;
Plugin[method].apply(this, Array.prototype.slice.call(arguments, 1));
}
} else {
if (!datatable.data(pluginName) && !$(this).hasClass(pfx + 'datatable--loaded')) {
datatable.dataSet = null;
datatable.textAlign = {
left: pfx + 'datatable__cell--left',
center: pfx + 'datatable__cell--center',
right: pfx + 'datatable__cell--right',
};
// merge default and user defined options
options = $.extend(true, {}, $.fn[pluginName].defaults, options);
datatable.options = options;
// init plugin process
Plugin.init.apply(this, [options]);
$(datatable.wrap).data(pluginName, datatable);
}
}
} else {
// get existing instance datatable
datatable = $(this).data(pluginName);
if (typeof datatable === 'undefined') {
$.error(pluginName + ' not initialized');
}
options = datatable.options;
}
return datatable;
};
// default options
$.fn[pluginName].defaults = {
// datasource definition
data: {
type: 'local',
source: null,
pageSize: 10, // display records per page
saveState: {
// save datatable state(pagination, filtering, sorting, etc) in cookie or browser webstorage
cookie: false,
webstorage: true,
},
serverPaging: false,
serverFiltering: false,
serverSorting: false,
autoColumns: false,
attr: {
rowProps: [],
},
},
// layout definition
layout: {
theme: 'default', // datatable will support multiple themes and designs
class: pfx + 'datatable--brand', // custom wrapper class
scroll: false, // enable/disable datatable scroll both horizontal and vertical when needed.
height: null, // datatable's body's fixed height
minHeight: 300,
footer: false, // display/hide footer
header: true, // display/hide header
customScrollbar: true, // set false to disable custom scrollbar
// datatable spinner
spinner: {
overlayColor: '#000000',
opacity: 0,
type: 'loader',
state: 'brand',
message: true,
},
// datatable UI icons
icons: {
sort: {asc: 'la la-arrow-up', desc: 'la la-arrow-down'},
pagination: {
next: 'la la-angle-right',
prev: 'la la-angle-left',
first: 'la la-angle-double-left',
last: 'la la-angle-double-right',
more: 'la la-ellipsis-h',
},
rowDetail: {expand: 'fa fa-caret-down', collapse: 'fa fa-caret-right'},
},
},
// column sorting
sortable: true,
// resize column size with mouse drag coming soon)
resizable: false,
// column based filtering (coming soon)
filterable: false,
pagination: true,
// inline and bactch editing (cooming soon)
editable: false,
// columns definition
columns: [],
search: {
// enable trigger search by keyup enter
onEnter: false,
// input text for search
input: null,
// search delay in milliseconds
delay: 400,
},
rows: {
// deprecated
callback: function() {
},
// call before row template
beforeTemplate: function() {
},
// call after row template
afterTemplate: function() {
},
// auto hide columns, if rows overflow. work on non locked columns
autoHide: false,
},
// toolbar
toolbar: {
// place pagination and displayInfo blocks according to the array order
layout: ['pagination', 'info'],
// toolbar placement can be at top or bottom or both top and bottom repeated
placement: ['bottom'], //'top', 'bottom'
// toolbar items
items: {
// pagination
pagination: {
// pagination type(default or scroll)
type: 'default',
// number of pages to display by breakpoints
pages: {
desktop: {
layout: 'default',
pagesNumber: 6,
},
tablet: {
layout: 'default',
pagesNumber: 3,
},
mobile: {
layout: 'compact',
},
},
// navigation buttons
navigation: {
prev: true, // display prev link
next: true, // display next link
first: true, // display first link
last: true, // display last link
},
// page size select
pageSizeSelect: [], // display dropdown to select pagination size. -1 is used for "ALl" option
},
// records info
info: true,
},
},
// here we will keep all strings and message used by datatable UI so developer can easiliy translate to any language.
// By default the stirngs will be in the plugin source and here can override it
translate: {
records: {
processing: 'Please wait...',
noRecords: 'No records found',
},
toolbar: {
pagination: {
items: {
default: {
first: 'First',
prev: 'Previous',
next: 'Next',
last: 'Last',
more: 'More pages',
input: 'Page number',
select: 'Select page size',
},
info: 'Displaying {{start}} - {{end}} of {{total}} records',
},
},
},
},
extensions: {},
};
}(jQuery));
var defaults = {
layout: {
icons: {
pagination: {
next: 'la la-angle-right',
prev: 'la la-angle-left',
first: 'la la-angle-double-left',
last: 'la la-angle-double-right',
more: 'la la-ellipsis-h',
},
rowDetail: {expand: 'fa fa-caret-down', collapse: 'fa fa-caret-right'},
}
}
};
if (mUtil.isRTL()) {
defaults = {
layout: {
icons: {
pagination: {
next: 'la la-angle-left',
prev: 'la la-angle-right',
last: 'la la-angle-double-left',
first: 'la la-angle-double-right',
},
rowDetail: {collapse: 'fa fa-caret-down', expand: 'fa fa-caret-right'},
}
}
}
}
$.extend(true, $.fn.mDatatable.defaults, defaults);
var mDropdown = function(elementId, options) {
//== Main object
var the = this;
var init = false;
//== Get element object
var element = mUtil.get(elementId);
var body = mUtil.get('body');
if (!element) {
return;
}
//== Default options
var defaultOptions = {
toggle: 'click',
hoverTimeout: 300,
skin: 'light',
height: 'auto',
maxHeight: false,
minHeight: false,
persistent: false,
mobileOverlay: true
};
////////////////////////////
// ** Private Methods ** //
////////////////////////////
var Plugin = {
/**
* Run plugin
* @returns {mdropdown}
*/
construct: function(options) {
if (mUtil.data(element).has('dropdown')) {
the = mUtil.data(element).get('dropdown');
} else {
// reset dropdown
Plugin.init(options);
Plugin.setup();
mUtil.data(element).set('dropdown', the);
}
return the;
},
/**
* Handles subdropdown click toggle
* @returns {mdropdown}
*/
init: function(options) {
// merge default and user defined options
the.options = mUtil.deepExtend({}, defaultOptions, options);
the.events = [];
the.eventHandlers = {};
the.open = false;
the.layout = {};
the.layout.close = mUtil.find(element, '.m-dropdown__close');
the.layout.toggle = mUtil.find(element, '.m-dropdown__toggle');
the.layout.arrow = mUtil.find(element, '.m-dropdown__arrow');
the.layout.wrapper = mUtil.find(element, '.m-dropdown__wrapper');
the.layout.defaultDropPos = mUtil.hasClass(element, 'm-dropdown--up') ? 'up' : 'down';
the.layout.currentDropPos = the.layout.defaultDropPos;
if (mUtil.attr(element, 'm-dropdown-toggle') == "hover") {
the.options.toggle = 'hover';
}
},
/**
* Setup dropdown
*/
setup: function() {
if (the.options.placement) {
mUtil.addClass(element, 'm-dropdown--' + the.options.placement);
}
if (the.options.align) {
mUtil.addClass(element, 'm-dropdown--align-' + the.options.align);
}
if (the.options.width) {
mUtil.css(the.layout.wrapper, 'width', the.options.width + 'px');
}
if (mUtil.attr(element, 'm-dropdown-persistent') == '1') {
the.options.persistent = true;
}
if (the.options.toggle == 'hover') {
mUtil.addEvent(element, 'mouseout', Plugin.hideMouseout);
}
// set zindex
Plugin.setZindex();
},
/**
* Toggle dropdown
*/
toggle: function() {
if (the.open) {
return Plugin.hide();
} else {
return Plugin.show();
}
},
/**
* Set content
*/
setContent: function(content) {
var content = mUtil.find(element, '.m-dropdown__content').innerHTML = content;
return the;
},
/**
* Show dropdown
*/
show: function () {
if (the.options.toggle == 'hover' && mUtil.hasAttr(element, 'hover')) {
Plugin.clearHovered();
return the;
}
if (the.open) {
return the;
}
if (the.layout.arrow) {
Plugin.adjustArrowPos();
}
Plugin.eventTrigger('beforeShow');
Plugin.hideOpened();
mUtil.addClass(element, 'm-dropdown--open');
if (mUtil.isMobileDevice() && the.options.mobileOverlay) {
var zIndex = mUtil.css(element, 'z-index') - 1;
var dropdownoff = mUtil.insertAfter(document.createElement('DIV'), element );
mUtil.addClass(dropdownoff, 'm-dropdown__dropoff');
mUtil.css(dropdownoff, 'z-index', zIndex);
mUtil.data(dropdownoff).set('dropdown', element);
mUtil.data(element).set('dropoff', dropdownoff);
mUtil.addEvent(dropdownoff, 'click', function(e) {
Plugin.hide();
mUtil.remove(this);
e.preventDefault();
});
}
element.focus();
element.setAttribute('aria-expanded', 'true');
the.open = true;
//== Update scrollers
mUtil.scrollersUpdate(element);
Plugin.eventTrigger('afterShow');
return the;
},
/**
* Clear dropdown hover
*/
clearHovered: function() {
var timeout = mUtil.attr(element, 'timeout');
mUtil.removeAttr(element, 'hover');
mUtil.removeAttr(element, 'timeout');
clearTimeout(timeout);
},
/**
* Hide hovered dropdown
*/
hideHovered: function(force) {
if (force === true) {
if (Plugin.eventTrigger('beforeHide') === false) {
return;
}
Plugin.clearHovered();
mUtil.removeClass(element, 'm-dropdown--open');
the.open = false;
Plugin.eventTrigger('afterHide');
} else {
if (mUtil.hasAttr(element, 'hover') === true) {
return;
}
if (Plugin.eventTrigger('beforeHide') === false) {
return;
}
var timeout = setTimeout(function() {
if (mUtil.attr(element, 'hover')) {
Plugin.clearHovered();
mUtil.removeClass(element, 'm-dropdown--open');
the.open = false;
Plugin.eventTrigger('afterHide');
}
}, the.options.hoverTimeout);
mUtil.attr(element, 'hover', '1');
mUtil.attr(element, 'timeout', timeout);
}
},
/**
* Hide clicked dropdown
*/
hideClicked: function() {
if (Plugin.eventTrigger('beforeHide') === false) {
return;
}
mUtil.removeClass(element, 'm-dropdown--open');
mUtil.data(element).remove('dropoff');
the.open = false;
Plugin.eventTrigger('afterHide');
},
/**
* Hide dropdown
*/
hide: function(force) {
if (the.open === false) {
return the;
}
if (mUtil.isDesktopDevice() && the.options.toggle == 'hover') {
Plugin.hideHovered(force);
} else {
Plugin.hideClicked();
}
if (the.layout.defaultDropPos == 'down' && the.layout.currentDropPos == 'up') {
mUtil.removeClass(element, 'm-dropdown--up');
the.layout.arrow.prependTo(the.layout.wrapper);
the.layout.currentDropPos = 'down';
}
return the;
},
/**
* Hide on mouseout
*/
hideMouseout: function() {
if (mUtil.isDesktopDevice()) {
Plugin.hide();
}
},
/**
* Hide opened dropdowns
*/
hideOpened: function() {
var query = mUtil.findAll(body, '.m-dropdown.m-dropdown--open');
for (var i = 0, j = query.length; i < j; i++) {
var dropdown = query[i];
mUtil.data(dropdown).get('dropdown').hide(true);
}
},
/**
* Adjust dropdown arrow positions
*/
adjustArrowPos: function() {
var width = mUtil.outerWidth(element); // ?
var alignment = mUtil.hasClass(the.layout.arrow, 'm-dropdown__arrow--right') ? 'right' : 'left';
var pos = 0;
if (the.layout.arrow) {
if ( mUtil.isInResponsiveRange('mobile') && mUtil.hasClass(element, 'm-dropdown--mobile-full-width') ) {
pos = mUtil.offset(element).left + (width / 2) - Math.abs( parseInt(mUtil.css(the.layout.arrow, 'width')) / 2) - parseInt(mUtil.css(the.layout.wrapper, 'left'));
mUtil.css(the.layout.arrow, 'right', 'auto');
mUtil.css(the.layout.arrow, 'left', pos + 'px');
mUtil.css(the.layout.arrow, 'margin-left', 'auto');
mUtil.css(the.layout.arrow, 'margin-right', 'auto');
} else if (mUtil.hasClass(the.layout.arrow, 'm-dropdown__arrow--adjust')) {
pos = width / 2 - Math.abs( parseInt(mUtil.css(the.layout.arrow, 'width')) / 2);
if (mUtil.hasClass(element, 'm-dropdown--align-push')) {
pos = pos + 20;
}
if (alignment == 'right') {
if (mUtil.isRTL()) {
mUtil.css(the.layout.arrow, 'right', 'auto');
mUtil.css(the.layout.arrow, 'left', pos + 'px');
} else {
mUtil.css(the.layout.arrow, 'left', 'auto');
mUtil.css(the.layout.arrow, 'right', pos + 'px');
}
} else {
if (mUtil.isRTL()) {
mUtil.css(the.layout.arrow, 'left', 'auto');
mUtil.css(the.layout.arrow, 'right', pos + 'px');
} else {
mUtil.css(the.layout.arrow, 'right', 'auto');
mUtil.css(the.layout.arrow, 'left', pos + 'px');
}
}
}
}
},
/**
* Get zindex
*/
setZindex: function() {
var zIndex = 101; //mUtil.css(the.layout.wrapper, 'z-index');
var newZindex = mUtil.getHighestZindex(element);
if (newZindex >= zIndex) {
zIndex = newZindex + 1;
}
mUtil.css(the.layout.wrapper, 'z-index', zIndex);
},
/**
* Check persistent
*/
isPersistent: function() {
return the.options.persistent;
},
/**
* Check persistent
*/
isShown: function() {
return the.open;
},
/**
* Trigger events
*/
eventTrigger: function(name, args) {
for (var i = 0; i < the.events.length; i++) {
var event = the.events[i];
if (event.name == name) {
if (event.one == true) {
if (event.fired == false) {
the.events[i].fired = true;
event.handler.call(this, the, args);
}
} else {
event.handler.call(this, the, args);
}
}
}
},
addEvent: function(name, handler, one) {
the.events.push({
name: name,
handler: handler,
one: one,
fired: false
});
}
};
//////////////////////////
// ** Public Methods ** //
//////////////////////////
/**
* Set default options
*/
the.setDefaults = function(options) {
defaultOptions = options;
};
/**
* Show dropdown
* @returns {mDropdown}
*/
the.show = function() {
return Plugin.show();
};
/**
* Hide dropdown
* @returns {mDropdown}
*/
the.hide = function() {
return Plugin.hide();
};
/**
* Toggle dropdown
* @returns {mDropdown}
*/
the.toggle = function() {
return Plugin.toggle();
};
/**
* Toggle dropdown
* @returns {mDropdown}
*/
the.isPersistent = function() {
return Plugin.isPersistent();
};
/**
* Check shown state
* @returns {mDropdown}
*/
the.isShown = function() {
return Plugin.isShown();
};
/**
* Set dropdown content
* @returns {mDropdown}
*/
the.setContent = function(content) {
return Plugin.setContent(content);
};
/**
* Register event
*/
the.on = function(name, handler) {
return Plugin.addEvent(name, handler);
};
/**
* Register event
*/
the.one = function(name, handler) {
return Plugin.addEvent(name, handler, true);
};
///////////////////////////////
// ** Plugin Construction ** //
///////////////////////////////
//== Run plugin
Plugin.construct.apply(the, [options]);
//== Init done
init = true;
// Return plugin instance
return the;
};
//== Plugin global lazy initialization
mUtil.on(document, '[m-dropdown-toggle="click"] .m-dropdown__toggle', 'click', function(e) {
var element = this.closest('.m-dropdown');
var dropdown;
if (element) {
if (mUtil.data(element).has('dropdown')) {
dropdown = mUtil.data(element).get('dropdown');
} else {
dropdown = new mDropdown(element);
}
dropdown.toggle();
e.preventDefault();
}
});
mUtil.on(document, '[m-dropdown-toggle="hover"] .m-dropdown__toggle', 'click', function(e) {
if (mUtil.isDesktopDevice()) {
if (mUtil.attr(this, 'href') == '#') {
e.preventDefault();
}
} else if (mUtil.isMobileDevice()) {
var element = this.closest('.m-dropdown');
var dropdown;
if (element) {
if (mUtil.data(element).has('dropdown')) {
dropdown = mUtil.data(element).get('dropdown');
} else {
dropdown = new mDropdown(element);
}
dropdown.toggle();
e.preventDefault();
}
}
});
mUtil.on(document, '[m-dropdown-toggle="hover"]', 'mouseover', function(e) {
if (mUtil.isDesktopDevice()) {
var element = this;
var dropdown;
if (element) {
if (mUtil.data(element).has('dropdown')) {
dropdown = mUtil.data(element).get('dropdown');
} else {
dropdown = new mDropdown(element);
}
dropdown.show();
e.preventDefault();
}
}
});
document.addEventListener("click", function(e) {
var query;
var body = mUtil.get('body');
var target = e.target;
//== Handle dropdown close
if (query = body.querySelectorAll('.m-dropdown.m-dropdown--open')) {
for (var i = 0, len = query.length; i < len; i++) {
var element = query[i];
if (mUtil.data(element).has('dropdown') === false) {
return;
}
var the = mUtil.data(element).get('dropdown');
var toggle = mUtil.find(element, '.m-dropdown__toggle');
if (mUtil.hasClass(element, 'm-dropdown--disable-close')) {
e.preventDefault();
e.stopPropagation();
//return;
}
if (toggle && target !== toggle && toggle.contains(target) === false && target.contains(toggle) === false) {
if (the.isPersistent() === false) {
the.hide();
}
} else if (element.contains(target) === false) {
the.hide();
}
}
}
});
var mHeader = function(elementId, options) {
//== Main object
var the = this;
var init = false;
//== Get element object
var element = mUtil.get(elementId);
var body = mUtil.get('body');
if (element === undefined) {
return;
}
//== Default options
var defaultOptions = {
classic: false,
offset: {
mobile: 150,
desktop: 200
},
minimize: {
mobile: false,
desktop: false
}
};
////////////////////////////
// ** Private Methods ** //
////////////////////////////
var Plugin = {
/**
* Run plugin
* @returns {mHeader}
*/
construct: function(options) {
if (mUtil.data(element).has('header')) {
the = mUtil.data(element).get('header');
} else {
// reset header
Plugin.init(options);
// build header
Plugin.build();
mUtil.data(element).set('header', the);
}
return the;
},
/**
* Handles subheader click toggle
* @returns {mHeader}
*/
init: function(options) {
the.events = [];
// merge default and user defined options
the.options = mUtil.deepExtend({}, defaultOptions, options);
},
/**
* Reset header
* @returns {mHeader}
*/
build: function() {
var lastScrollTop = 0;
if (the.options.minimize.mobile === false && the.options.minimize.desktop === false) {
return;
}
window.addEventListener('scroll', function() {
var offset = 0, on, off, st;
if (mUtil.isInResponsiveRange('desktop')) {
offset = the.options.offset.desktop;
on = the.options.minimize.desktop.on;
off = the.options.minimize.desktop.off;
} else if (mUtil.isInResponsiveRange('tablet-and-mobile')) {
offset = the.options.offset.mobile;
on = the.options.minimize.mobile.on;
off = the.options.minimize.mobile.off;
}
st = window.pageYOffset;
if (
(mUtil.isInResponsiveRange('tablet-and-mobile') && the.options.classic && the.options.classic.mobile) ||
(mUtil.isInResponsiveRange('desktop') && the.options.classic && the.options.classic.desktop)
) {
if (st > offset) { // down scroll mode
mUtil.addClass(body, on);
mUtil.removeClass(body, off);
} else { // back scroll mode
mUtil.addClass(body, off);
mUtil.removeClass(body, on);
}
} else {
if (st > offset && lastScrollTop < st) { // down scroll mode
mUtil.addClass(body, on);
mUtil.removeClass(body, off);
} else { // back scroll mode
mUtil.addClass(body, off);
mUtil.removeClass(body, on);
}
lastScrollTop = st;
}
});
},
/**
* Trigger events
*/
eventTrigger: function(name, args) {
for (var i = 0; i < the.events.length; i++) {
var event = the.events[i];
if (event.name == name) {
if (event.one == true) {
if (event.fired == false) {
the.events[i].fired = true;
event.handler.call(this, the, args);
}
} else {
event.handler.call(this, the, args);
}
}
}
},
addEvent: function(name, handler, one) {
the.events.push({
name: name,
handler: handler,
one: one,
fired: false
});
}
};
//////////////////////////
// ** Public Methods ** //
//////////////////////////
/**
* Set default options
*/
the.setDefaults = function(options) {
defaultOptions = options;
};
/**
* Register event
*/
the.on = function(name, handler) {
return Plugin.addEvent(name, handler);
};
///////////////////////////////
// ** Plugin Construction ** //
///////////////////////////////
//== Run plugin
Plugin.construct.apply(the, [options]);
//== Init done
init = true;
// Return plugin instance
return the;
};
var mMenu = function(elementId, options) {
//== Main object
var the = this;
var init = false;
//== Get element object
var element = mUtil.get(elementId);
var body = mUtil.get('body');
if (!element) {
return;
}
//== Default options
var defaultOptions = {
// accordion submenu mode
accordion: {
slideSpeed: 200, // accordion toggle slide speed in milliseconds
autoScroll: false, // enable auto scrolling(focus) to the clicked menu item
autoScrollSpeed: 1200,
expandAll: true // allow having multiple expanded accordions in the menu
},
// dropdown submenu mode
dropdown: {
timeout: 500 // timeout in milliseconds to show and hide the hoverable submenu dropdown
}
};
////////////////////////////
// ** Private Methods ** //
////////////////////////////
var Plugin = {
/**
* Run plugin
* @returns {mMenu}
*/
construct: function(options) {
if (mUtil.data(element).has('menu')) {
the = mUtil.data(element).get('menu');
} else {
// reset menu
Plugin.init(options);
// reset menu
Plugin.reset();
// build menu
Plugin.build();
mUtil.data(element).set('menu', the);
}
return the;
},
/**
* Handles submenu click toggle
* @returns {mMenu}
*/
init: function(options) {
the.events = [];
the.eventHandlers = {};
// merge default and user defined options
the.options = mUtil.deepExtend({}, defaultOptions, options);
// pause menu
the.pauseDropdownHoverTime = 0;
the.uid = mUtil.getUniqueID();
},
update: function(options) {
// merge default and user defined options
the.options = mUtil.deepExtend({}, defaultOptions, options);
// pause menu
the.pauseDropdownHoverTime = 0;
// reset menu
Plugin.reset();
the.eventHandlers = {};
// build menu
Plugin.build();
mUtil.data(element).set('menu', the);
},
reload: function() {
// reset menu
Plugin.reset();
// build menu
Plugin.build();
},
/**
* Reset menu
* @returns {mMenu}
*/
build: function() {
//== General accordion submenu toggle
the.eventHandlers['event_1'] = mUtil.on( element, '.m-menu__toggle', 'click', Plugin.handleSubmenuAccordion);
//== Dropdown mode(hoverable)
if (Plugin.getSubmenuMode() === 'dropdown' || Plugin.isConditionalSubmenuDropdown()) {
// dropdown submenu - hover toggle
the.eventHandlers['event_2'] = mUtil.on( element, '[m-menu-submenu-toggle="hover"]', 'mouseover', Plugin.handleSubmenuDrodownHoverEnter);
the.eventHandlers['event_3'] = mUtil.on( element, '[m-menu-submenu-toggle="hover"]', 'mouseout', Plugin.handleSubmenuDrodownHoverExit);
// dropdown submenu - click toggle
the.eventHandlers['event_4'] = mUtil.on( element, '[m-menu-submenu-toggle="click"] > .m-menu__toggle, [m-menu-submenu-toggle="click"] > .m-menu__link .m-menu__toggle', 'click', Plugin.handleSubmenuDropdownClick);
the.eventHandlers['event_5'] = mUtil.on( element, '[m-menu-submenu-toggle="tab"] > .m-menu__toggle, [m-menu-submenu-toggle="tab"] > .m-menu__link .m-menu__toggle', 'click', Plugin.handleSubmenuDropdownTabClick);
}
//== General link click
the.eventHandlers['event_6'] = mUtil.on(element, '.m-menu__item:not(.m-menu__item--submenu) > .m-menu__link:not(.m-menu__toggle):not(.m-menu__link--toggle-skip)', 'click', Plugin.handleLinkClick);
//== Init scrollable menu
if (the.options.scroll && the.options.scroll.height) {
Plugin.scrollerInit();
}
},
/**
* Reset menu
* @returns {mMenu}
*/
reset: function() {
mUtil.off( element, 'click', the.eventHandlers['event_1']);
// dropdown submenu - hover toggle
mUtil.off( element, 'mouseover', the.eventHandlers['event_2']);
mUtil.off( element, 'mouseout', the.eventHandlers['event_3']);
// dropdown submenu - click toggle
mUtil.off( element, 'click', the.eventHandlers['event_4']);
mUtil.off( element, 'click', the.eventHandlers['event_5']);
mUtil.off(element, 'click', the.eventHandlers['event_6']);
},
/**
* Init scroll menu
*
*/
scrollerInit: function() {
if ( the.options.scroll && the.options.scroll.height ) {
mUtil.scrollerDestroy(element);
mUtil.scrollerInit(element, {disableForMobile: true, resetHeightOnDestroy: true, handleWindowResize: true, height: the.options.scroll.height});
}
},
/**
* Update scroll menu
*/
scrollerUpdate: function() {
if ( the.options.scroll && the.options.scroll.height ) {
mUtil.scrollerUpdate(element);
} else {
mUtil.scrollerDestroy(element);
}
},
/**
* Scroll top
*/
scrollerTop: function() {
if ( the.options.scroll && the.options.scroll.height ) {
mUtil.scrollerTop(element);
}
},
/**
* Get submenu mode for current breakpoint and menu state
* @returns {mMenu}
*/
getSubmenuMode: function(el) {
if ( mUtil.isInResponsiveRange('desktop') ) {
if (el && mUtil.hasAttr(el, 'm-menu-submenu-toggle')) {
return mUtil.attr(el, 'm-menu-submenu-toggle');
}
if ( mUtil.isset(the.options.submenu, 'desktop.state.body') ) {
if ( mUtil.hasClass(body, the.options.submenu.desktop.state.body) ) {
return the.options.submenu.desktop.state.mode;
} else {
return the.options.submenu.desktop.default;
}
} else if ( mUtil.isset(the.options.submenu, 'desktop') ) {
return the.options.submenu.desktop;
}
} else if ( mUtil.isInResponsiveRange('tablet') && mUtil.isset(the.options.submenu, 'tablet') ) {
return the.options.submenu.tablet;
} else if ( mUtil.isInResponsiveRange('mobile') && mUtil.isset(the.options.submenu, 'mobile') ) {
return the.options.submenu.mobile;
} else {
return false;
}
},
/**
* Get submenu mode for current breakpoint and menu state
* @returns {mMenu}
*/
isConditionalSubmenuDropdown: function() {
if ( mUtil.isInResponsiveRange('desktop') && mUtil.isset(the.options.submenu, 'desktop.state.body') ) {
return true;
} else {
return false;
}
},
/**
* Handles menu link click
* @returns {mMenu}
*/
handleLinkClick: function(e) {
if ( Plugin.eventTrigger('linkClick', this) === false ) {
e.preventDefault();
};
if ( Plugin.getSubmenuMode(this) === 'dropdown' || Plugin.isConditionalSubmenuDropdown() ) {
Plugin.handleSubmenuDropdownClose(e, this);
}
},
/**
* Handles submenu hover toggle
* @returns {mMenu}
*/
handleSubmenuDrodownHoverEnter: function(e) {
if ( Plugin.getSubmenuMode(this) === 'accordion' ) {
return;
}
if ( the.resumeDropdownHover() === false ) {
return;
}
var item = this;
if ( item.getAttribute('data-hover') == '1' ) {
item.removeAttribute('data-hover');
clearTimeout( item.getAttribute('data-timeout') );
item.removeAttribute('data-timeout');
//Plugin.hideSubmenuDropdown(item, false);
}
Plugin.showSubmenuDropdown(item);
},
/**
* Handles submenu hover toggle
* @returns {mMenu}
*/
handleSubmenuDrodownHoverExit: function(e) {
if ( the.resumeDropdownHover() === false ) {
return;
}
if ( Plugin.getSubmenuMode(this) === 'accordion' ) {
return;
}
var item = this;
var time = the.options.dropdown.timeout;
var timeout = setTimeout(function() {
if ( item.getAttribute('data-hover') == '1' ) {
Plugin.hideSubmenuDropdown(item, true);
}
}, time);
item.setAttribute('data-hover', '1');
item.setAttribute('data-timeout', timeout);
},
/**
* Handles submenu click toggle
* @returns {mMenu}
*/
handleSubmenuDropdownClick: function(e) {
if ( Plugin.getSubmenuMode(this) === 'accordion' ) {
return;
}
var item = this.closest('.m-menu__item');
if ( item.getAttribute('m-menu-submenu-mode') == 'accordion' ) {
return;
}
if ( mUtil.hasClass(item, 'm-menu__item--hover') === false ) {
mUtil.addClass(item, 'm-menu__item--open-dropdown');
Plugin.showSubmenuDropdown(item);
} else {
mUtil.removeClass(item, 'm-menu__item--open-dropdown' );
Plugin.hideSubmenuDropdown(item, true);
}
e.preventDefault();
},
/**
* Handles tab click toggle
* @returns {mMenu}
*/
handleSubmenuDropdownTabClick: function(e) {
if (Plugin.getSubmenuMode(this) === 'accordion') {
return;
}
var item = this.closest('.m-menu__item');
if (item.getAttribute('m-menu-submenu-mode') == 'accordion') {
return;
}
if (mUtil.hasClass(item, 'm-menu__item--hover') == false) {
mUtil.addClass(item, 'm-menu__item--open-dropdown');
Plugin.showSubmenuDropdown(item);
}
e.preventDefault();
},
/**
* Handles submenu dropdown close on link click
* @returns {mMenu}
*/
handleSubmenuDropdownClose: function(e, el) {
// exit if its not submenu dropdown mode
if (Plugin.getSubmenuMode(el) === 'accordion') {
return;
}
var shown = element.querySelectorAll('.m-menu__item.m-menu__item--submenu.m-menu__item--hover:not(.m-menu__item--tabs)');
// check if currently clicked link's parent item ha
if (shown.length > 0 && mUtil.hasClass(el, 'm-menu__toggle') === false && el.querySelectorAll('.m-menu__toggle').length === 0) {
// close opened dropdown menus
for (var i = 0, len = shown.length; i < len; i++) {
Plugin.hideSubmenuDropdown(shown[0], true);
}
}
},
/**
* helper functions
* @returns {mMenu}
*/
handleSubmenuAccordion: function(e, el) {
var query;
var item = el ? el : this;
if ( Plugin.getSubmenuMode(el) === 'dropdown' && (query = item.closest('.m-menu__item') ) ) {
if (query.getAttribute('m-menu-submenu-mode') != 'accordion' ) {
e.preventDefault();
return;
}
}
var li = item.closest('.m-menu__item');
var submenu = mUtil.child(li, '.m-menu__submenu, .m-menu__inner');
if (mUtil.hasClass(item.closest('.m-menu__item'), 'm-menu__item--open-always')) {
return;
}
if ( li && submenu ) {
e.preventDefault();
var speed = the.options.accordion.slideSpeed;
var hasClosables = false;
if ( mUtil.hasClass(li, 'm-menu__item--open') === false ) {
// hide other accordions
if ( the.options.accordion.expandAll === false ) {
var subnav = item.closest('.m-menu__nav, .m-menu__subnav');
var closables = mUtil.children(subnav, '.m-menu__item.m-menu__item--open.m-menu__item--submenu:not(.m-menu__item--expanded):not(.m-menu__item--open-always)');
if ( subnav && closables ) {
for (var i = 0, len = closables.length; i < len; i++) {
var el_ = closables[0];
var submenu_ = mUtil.child(el_, '.m-menu__submenu');
if ( submenu_ ) {
mUtil.slideUp(submenu_, speed, function() {
Plugin.scrollerUpdate();
mUtil.removeClass(el_, 'm-menu__item--open');
});
}
}
}
}
mUtil.slideDown(submenu, speed, function() {
Plugin.scrollToItem(item);
Plugin.scrollerUpdate();
Plugin.eventTrigger('submenuToggle', submenu);
});
mUtil.addClass(li, 'm-menu__item--open');
} else {
mUtil.slideUp(submenu, speed, function() {
Plugin.scrollToItem(item);
Plugin.eventTrigger('submenuToggle', submenu);
});
mUtil.removeClass(li, 'm-menu__item--open');
}
}
},
/**
* scroll to item function
* @returns {mMenu}
*/
scrollToItem: function(item) {
// handle auto scroll for accordion submenus
if ( mUtil.isInResponsiveRange('desktop') && the.options.accordion.autoScroll && element.getAttribute('m-menu-scrollable') !== '1' ) {
mUtil.scrollTo(item, the.options.accordion.autoScrollSpeed);
}
},
/**
* helper functions
* @returns {mMenu}
*/
hideSubmenuDropdown: function(item, classAlso) {
// remove submenu activation class
if ( classAlso ) {
mUtil.removeClass(item, 'm-menu__item--hover');
mUtil.removeClass(item, 'm-menu__item--active-tab');
}
// clear timeout
item.removeAttribute('data-hover');
if ( item.getAttribute('m-menu-dropdown-toggle-class') ) {
mUtil.removeClass(body, item.getAttribute('m-menu-dropdown-toggle-class'));
}
var timeout = item.getAttribute('data-timeout');
item.removeAttribute('data-timeout');
clearTimeout(timeout);
},
/**
* helper functions
* @returns {mMenu}
*/
showSubmenuDropdown: function(item) {
// close active submenus
var list = element.querySelectorAll('.m-menu__item--submenu.m-menu__item--hover, .m-menu__item--submenu.m-menu__item--active-tab');
if ( list ) {
for (var i = 0, len = list.length; i < len; i++) {
var el = list[i];
if ( item !== el && el.contains(item) === false && item.contains(el) === false ) {
Plugin.hideSubmenuDropdown(el, true);
}
}
}
// adjust submenu position
Plugin.adjustSubmenuDropdownArrowPos(item);
// add submenu activation class
mUtil.addClass(item, 'm-menu__item--hover');
if ( item.getAttribute('m-menu-dropdown-toggle-class') ) {
mUtil.addClass(body, item.getAttribute('m-menu-dropdown-toggle-class'));
}
},
/**
* Handles submenu slide toggle
* @returns {mMenu}
*/
createSubmenuDropdownClickDropoff: function(el) {
var query;
var zIndex = (query = mUtil.child(el, '.m-menu__submenu') ? mUtil.css(query, 'z-index') : 0) - 1;
var dropoff = document.createElement('');
body.appendChild(dropoff);
mUtil.addEvent(dropoff, 'click', function(e) {
e.stopPropagation();
e.preventDefault();
mUtil.remove(this);
Plugin.hideSubmenuDropdown(el, true);
});
},
/**
* Handles submenu click toggle
* @returns {mMenu}
*/
adjustSubmenuDropdownArrowPos: function(item) {
var submenu = mUtil.child(item, '.m-menu__submenu');
var arrow = mUtil.child( submenu, '.m-menu__arrow.m-menu__arrow--adjust');
var subnav = mUtil.child( submenu, '.m-menu__subnav');
if ( arrow ) {
var pos = 0;
var link = mUtil.child(item, '.m-menu__link');
if ( mUtil.hasClass(submenu, 'm-menu__submenu--classic') || mUtil.hasClass(submenu, 'm-menu__submenu--fixed') ) {
if ( mUtil.hasClass(submenu, 'm-menu__submenu--right')) {
pos = mUtil.outerWidth(item) / 2;
if (mUtil.hasClass(submenu, 'm-menu__submenu--pull')) {
if (mUtil.isRTL()) {
pos = pos + Math.abs( parseFloat(mUtil.css(submenu, 'margin-left')) );
} else {
pos = pos + Math.abs( parseFloat(mUtil.css(submenu, 'margin-right')) );
}
}
pos = parseInt(mUtil.css(submenu, 'width')) - pos;
} else if ( mUtil.hasClass(submenu, 'm-menu__submenu--left') ) {
pos = mUtil.outerWidth(item) / 2;
if ( mUtil.hasClass(submenu, 'm-menu__submenu--pull')) {
if (mUtil.isRTL()) {
pos = pos + Math.abs( parseFloat(mUtil.css(submenu, 'margin-right')) );
} else {
pos = pos + Math.abs( parseFloat(mUtil.css(submenu, 'margin-left')) );
}
}
}
if (mUtil.isRTL()) {
mUtil.css(arrow, 'right', pos + 'px');
} else {
mUtil.css(arrow, 'left', pos + 'px');
}
} else {
if ( mUtil.hasClass(submenu, 'm-menu__submenu--center') || mUtil.hasClass(submenu, 'm-menu__submenu--full') ) {
pos = mUtil.offset(item).left - ((mUtil.getViewPort().width - parseInt(mUtil.css(submenu, 'width'))) / 2);
pos = pos + (mUtil.outerWidth(item) / 2);
mUtil.css(arrow, 'left', pos + 'px');
if (mUtil.isRTL()) {
mUtil.css(arrow, 'right', 'auto');
}
}
}
}
},
/**
* Handles submenu hover toggle
* @returns {mMenu}
*/
pauseDropdownHover: function(time) {
var date = new Date();
the.pauseDropdownHoverTime = date.getTime() + time;
},
/**
* Handles submenu hover toggle
* @returns {mMenu}
*/
resumeDropdownHover: function() {
var date = new Date();
return (date.getTime() > the.pauseDropdownHoverTime ? true : false);
},
/**
* Reset menu's current active item
* @returns {mMenu}
*/
resetActiveItem: function(item) {
var list;
var parents;
list = element.querySelectorAll('.m-menu__item--active');
for (var i = 0, len = list.length; i < len; i++) {
var el = list[0];
mUtil.removeClass(el, 'm-menu__item--active');
mUtil.hide( mUtil.child(el, '.m-menu__submenu') );
parents = mUtil.parents(el, '.m-menu__item--submenu');
for (var i_ = 0, len_ = parents.length; i_ < len_; i_++) {
var el_ = parents[i];
mUtil.removeClass(el_, 'm-menu__item--open');
mUtil.hide( mUtil.child(el_, '.m-menu__submenu') );
}
}
// close open submenus
if ( the.options.accordion.expandAll === false ) {
if ( list = element.querySelectorAll('.m-menu__item--open') ) {
for (var i = 0, len = list.length; i < len; i++) {
mUtil.removeClass(parents[0], 'm-menu__item--open');
}
}
}
},
/**
* Sets menu's active item
* @returns {mMenu}
*/
setActiveItem: function(item) {
// reset current active item
Plugin.resetActiveItem();
mUtil.addClass(item, 'm-menu__item--active');
var parents = mUtil.parents(item, '.m-menu__item--submenu');
for (var i = 0, len = parents.length; i < len; i++) {
mUtil.addClass(parents[i], 'm-menu__item--open');
}
},
/**
* Returns page breadcrumbs for the menu's active item
* @returns {mMenu}
*/
getBreadcrumbs: function(item) {
var query;
var breadcrumbs = [];
var link = mUtil.child(item, '.m-menu__link');
breadcrumbs.push({
text: (query = mUtil.child(link, '.m-menu__link-text') ? query.innerHTML : ''),
title: link.getAttribute('title'),
href: link.getAttribute('href')
});
var parents = mUtil.parents(item, '.m-menu__item--submenu');
for (var i = 0, len = parents.length; i < len; i++) {
var submenuLink = mUtil.child(parents[i], '.m-menu__link');
breadcrumbs.push({
text: (query = mUtil.child(submenuLink, '.m-menu__link-text') ? query.innerHTML : ''),
title: submenuLink.getAttribute('title'),
href: submenuLink.getAttribute('href')
});
}
return breadcrumbs.reverse();
},
/**
* Returns page title for the menu's active item
* @returns {mMenu}
*/
getPageTitle: function(item) {
var query;
return (query = mUtil.child(item, '.m-menu__link-text') ? query.innerHTML : '');
},
/**
* Trigger events
*/
eventTrigger: function(name, args) {
for (var i = 0; i < the.events.length; i++ ) {
var event = the.events[i];
if ( event.name == name ) {
if ( event.one == true ) {
if ( event.fired == false ) {
the.events[i].fired = true;
event.handler.call(this, the, args);
}
} else {
event.handler.call(this, the, args);
}
}
}
},
addEvent: function(name, handler, one) {
the.events.push({
name: name,
handler: handler,
one: one,
fired: false
});
},
removeEvent: function(name) {
if (the.events[name]) {
delete the.events[name];
}
}
};
//////////////////////////
// ** Public Methods ** //
//////////////////////////
/**
* Set default options
*/
the.setDefaults = function(options) {
defaultOptions = options;
};
/**
* Set active menu item
*/
the.scrollerUpdate = function() {
return Plugin.scrollerUpdate();
};
/**
* Set active menu item
*/
the.scrollerTop = function() {
return Plugin.scrollerTop();
};
/**
* Set active menu item
*/
the.setActiveItem = function(item) {
return Plugin.setActiveItem(item);
};
the.reload = function() {
return Plugin.reload();
};
the.update = function(options) {
return Plugin.update(options);
};
/**
* Set breadcrumb for menu item
*/
the.getBreadcrumbs = function(item) {
return Plugin.getBreadcrumbs(item);
};
/**
* Set page title for menu item
*/
the.getPageTitle = function(item) {
return Plugin.getPageTitle(item);
};
/**
* Get submenu mode
*/
the.getSubmenuMode = function(el) {
return Plugin.getSubmenuMode(el);
};
/**
* Hide dropdown submenu
* @returns {jQuery}
*/
the.hideDropdown = function(item) {
Plugin.hideSubmenuDropdown(item, true);
};
/**
* Disable menu for given time
* @returns {jQuery}
*/
the.pauseDropdownHover = function(time) {
Plugin.pauseDropdownHover(time);
};
/**
* Disable menu for given time
* @returns {jQuery}
*/
the.resumeDropdownHover = function() {
return Plugin.resumeDropdownHover();
};
/**
* Register event
*/
the.on = function(name, handler) {
return Plugin.addEvent(name, handler);
};
the.off = function(name) {
return Plugin.removeEvent(name);
};
the.one = function(name, handler) {
return Plugin.addEvent(name, handler, true);
};
///////////////////////////////
// ** Plugin Construction ** //
///////////////////////////////
//== Run plugin
Plugin.construct.apply(the, [options]);
//== Handle plugin on window resize
mUtil.addResizeHandler(function() {
if (init) {
the.reload();
}
});
//== Init done
init = true;
// Return plugin instance
return the;
};
// Plugin global lazy initialization
document.addEventListener("click", function (e) {
var body = mUtil.get('body');
var query;
if ( query = body.querySelectorAll('.m-menu__nav .m-menu__item.m-menu__item--submenu.m-menu__item--hover:not(.m-menu__item--tabs)[m-menu-submenu-toggle="click"]') ) {
for (var i = 0, len = query.length; i < len; i++) {
var element = query[i].closest('.m-menu__nav').parentNode;
if ( element ) {
var the = mUtil.data(element).get('menu');
if ( !the ) {
break;
}
if ( !the || the.getSubmenuMode() !== 'dropdown' ) {
break;
}
if ( e.target !== element && element.contains(e.target) === false ) {
var items;
if ( items = element.querySelectorAll('.m-menu__item--submenu.m-menu__item--hover:not(.m-menu__item--tabs)[m-menu-submenu-toggle="click"]') ) {
for (var j = 0, cnt = items.length; j < cnt; j++) {
the.hideDropdown(items[j]);
}
}
}
}
}
}
});
var mOffcanvas = function(elementId, options) {
//== Main object
var the = this;
var init = false;
//== Get element object
var element = mUtil.get(elementId);
var body = mUtil.get('body');
if (!element) {
return;
}
//== Default options
var defaultOptions = {};
////////////////////////////
// ** Private Methods ** //
////////////////////////////
var Plugin = {
/**
* Run plugin
* @returns {moffcanvas}
*/
construct: function(options) {
if (mUtil.data(element).has('offcanvas')) {
the = mUtil.data(element).get('offcanvas');
} else {
// reset offcanvas
Plugin.init(options);
// build offcanvas
Plugin.build();
mUtil.data(element).set('offcanvas', the);
}
return the;
},
/**
* Handles suboffcanvas click toggle
* @returns {moffcanvas}
*/
init: function(options) {
the.events = [];
// merge default and user defined options
the.options = mUtil.deepExtend({}, defaultOptions, options);
the.overlay;
the.classBase = the.options.baseClass;
the.classShown = the.classBase + '--on';
the.classOverlay = the.classBase + '-overlay';
the.state = mUtil.hasClass(element, the.classShown) ? 'shown' : 'hidden';
},
build: function() {
//== offcanvas toggle
if (the.options.toggleBy) {
if (typeof the.options.toggleBy === 'string') {
mUtil.addEvent( the.options.toggleBy, 'click', Plugin.toggle);
} else if (the.options.toggleBy && the.options.toggleBy[0] && the.options.toggleBy[0].target) {
for (var i in the.options.toggleBy) {
mUtil.addEvent( the.options.toggleBy[i].target, 'click', Plugin.toggle);
}
} else if (the.options.toggleBy && the.options.toggleBy.target) {
mUtil.addEvent( the.options.toggleBy.target, 'click', Plugin.toggle);
}
}
//== offcanvas close
var closeBy = mUtil.get(the.options.closeBy);
if (closeBy) {
mUtil.addEvent(closeBy, 'click', Plugin.hide);
}
},
/**
* Handles offcanvas toggle
*/
toggle: function() {;
Plugin.eventTrigger('toggle');
if (the.state == 'shown') {
Plugin.hide(this);
} else {
Plugin.show(this);
}
},
/**
* Handles offcanvas show
*/
show: function(target) {
if (the.state == 'shown') {
return;
}
Plugin.eventTrigger('beforeShow');
Plugin.togglerClass(target, 'show');
//== Offcanvas panel
mUtil.addClass(body, the.classShown);
mUtil.addClass(element, the.classShown);
the.state = 'shown';
if (the.options.overlay) {
the.overlay = mUtil.insertAfter(document.createElement('DIV') , element );
mUtil.addClass(the.overlay, the.classOverlay);
mUtil.addEvent(the.overlay, 'click', function(e) {
e.stopPropagation();
e.preventDefault();
Plugin.hide(target);
});
}
Plugin.eventTrigger('afterShow');
},
/**
* Handles offcanvas hide
*/
hide: function(target) {
if (the.state == 'hidden') {
return;
}
Plugin.eventTrigger('beforeHide');
Plugin.togglerClass(target, 'hide');
mUtil.removeClass(body, the.classShown);
mUtil.removeClass(element, the.classShown);
the.state = 'hidden';
if (the.options.overlay && the.overlay) {
mUtil.remove(the.overlay);
}
Plugin.eventTrigger('afterHide');
},
/**
* Handles toggler class
*/
togglerClass: function(target, mode) {
//== Toggler
var id = mUtil.attr(target, 'id');
var toggleBy;
if (the.options.toggleBy && the.options.toggleBy[0] && the.options.toggleBy[0].target) {
for (var i in the.options.toggleBy) {
if (the.options.toggleBy[i].target === id) {
toggleBy = the.options.toggleBy[i];
}
}
} else if (the.options.toggleBy && the.options.toggleBy.target) {
toggleBy = the.options.toggleBy;
}
if (toggleBy) {
var el = mUtil.get(toggleBy.target);
if (mode === 'show') {
mUtil.addClass(el, toggleBy.state);
}
if (mode === 'hide') {
mUtil.removeClass(el, toggleBy.state);
}
}
},
/**
* Trigger events
*/
eventTrigger: function(name, args) {
for (var i = 0; i < the.events.length; i++) {
var event = the.events[i];
if (event.name == name) {
if (event.one == true) {
if (event.fired == false) {
the.events[i].fired = true;
event.handler.call(this, the, args);
}
} else {
event.handler.call(this, the, args);
}
}
}
},
addEvent: function(name, handler, one) {
the.events.push({
name: name,
handler: handler,
one: one,
fired: false
});
}
};
//////////////////////////
// ** Public Methods ** //
//////////////////////////
/**
* Set default options
*/
the.setDefaults = function(options) {
defaultOptions = options;
};
/**
* Hide
*/
the.hide = function() {
return Plugin.hide();
};
/**
* Show
*/
the.show = function() {
return Plugin.show();
};
/**
* Get suboffcanvas mode
*/
the.on = function(name, handler) {
return Plugin.addEvent(name, handler);
};
/**
* Set offcanvas content
* @returns {mOffcanvas}
*/
the.one = function(name, handler) {
return Plugin.addEvent(name, handler, true);
};
///////////////////////////////
// ** Plugin Construction ** //
///////////////////////////////
//== Run plugin
Plugin.construct.apply(the, [options]);
//== Init done
init = true;
// Return plugin instance
return the;
};
// plugin setup
var mPortlet = function(elementId, options) {
//== Main object
var the = this;
var init = false;
//== Get element object
var element = mUtil.get(elementId);
var body = mUtil.get('body');
if (!element) {
return;
}
//== Default options
var defaultOptions = {
bodyToggleSpeed: 400,
tooltips: true,
tools: {
toggle: {
collapse: 'Collapse',
expand: 'Expand'
},
reload: 'Reload',
remove: 'Remove',
fullscreen: {
on: 'Fullscreen',
off: 'Exit Fullscreen'
}
},
sticky: {
offset: 300,
zIndex: 98
}
};
////////////////////////////
// ** Private Methods ** //
////////////////////////////
var Plugin = {
/**
* Construct
*/
construct: function(options) {
if (mUtil.data(element).has('portlet')) {
the = mUtil.data(element).get('portlet');
} else {
// reset menu
Plugin.init(options);
// build menu
Plugin.build();
mUtil.data(element).set('portlet', the);
}
return the;
},
/**
* Init portlet
*/
init: function(options) {
the.element = element;
the.events = [];
// merge default and user defined options
the.options = mUtil.deepExtend({}, defaultOptions, options);
the.head = mUtil.child(element, '.m-portlet__head');
the.foot = mUtil.child(element, '.m-portlet__foot');
if (mUtil.child(element, '.m-portlet__body')) {
the.body = mUtil.child(element, '.m-portlet__body');
} else if (mUtil.child(element, '.m-form').length !== 0) {
the.body = mUtil.child(element, '.m-form');
}
},
/**
* Build Form Wizard
*/
build: function() {
//== Remove
var remove = mUtil.find(the.head, '[m-portlet-tool=remove]');
if (remove) {
mUtil.addEvent(remove, 'click', function(e) {
e.preventDefault();
Plugin.remove();
});
}
//== Reload
var reload = mUtil.find(the.head, '[m-portlet-tool=reload]');
if (reload) {
mUtil.addEvent(reload, 'click', function(e) {
e.preventDefault();
Plugin.reload();
});
}
//== Toggle
var toggle = mUtil.find(the.head, '[m-portlet-tool=toggle]');
if (toggle) {
mUtil.addEvent(toggle, 'click', function(e) {
e.preventDefault();
Plugin.toggle();
});
}
//== Fullscreen
var fullscreen = mUtil.find(the.head, '[m-portlet-tool=fullscreen]');
if (fullscreen) {
mUtil.addEvent(fullscreen, 'click', function(e) {
e.preventDefault();
Plugin.fullscreen();
});
}
Plugin.setupTooltips();
},
/**
* Window scroll handle event for sticky portlet
*/
onScrollSticky: function() {
var st = window.pageYOffset;
var offset = the.options.sticky.offset;
if (st > offset) {
if (mUtil.hasClass(body, 'm-portlet--sticky') === false) {
Plugin.eventTrigger('stickyOn');
mUtil.addClass(body, 'm-portlet--sticky');
mUtil.addClass(element, 'm-portlet--sticky');
Plugin.updateSticky();
}
} else { // back scroll mode
if (mUtil.hasClass(body, 'm-portlet--sticky')) {
Plugin.eventTrigger('stickyOff');
mUtil.removeClass(body, 'm-portlet--sticky');
mUtil.removeClass(element, 'm-portlet--sticky');
Plugin.resetSticky();
}
}
},
/**
* Init sticky portlet
*/
initSticky: function() {
if (!the.head) {
return;
}
window.addEventListener('scroll', Plugin.onScrollSticky);
},
/**
* Update sticky portlet positions
*/
updateSticky: function() {
if (!the.head) {
return;
}
var top;
if (mUtil.hasClass(body, 'm-portlet--sticky')) {
if (the.options.sticky.position.top instanceof Function) {
top = parseInt(the.options.sticky.position.top.call());
} else {
top = parseInt(the.options.sticky.position.top);
}
var left;
if (the.options.sticky.position.left instanceof Function) {
left = parseInt(the.options.sticky.position.left.call());
} else {
left = parseInt(the.options.sticky.position.left);
}
var right;
if (the.options.sticky.position.right instanceof Function) {
right = parseInt(the.options.sticky.position.right.call());
} else {
right = parseInt(the.options.sticky.position.right);
}
mUtil.css(the.head, 'z-index', the.options.sticky.zIndex);
mUtil.css(the.head, 'top', top + 'px');
if (mUtil.isRTL()) {
mUtil.css(the.head, 'left', right + 'px');
mUtil.css(the.head, 'right',left + 'px');
} else {
mUtil.css(the.head, 'left', left + 'px');
mUtil.css(the.head, 'right', right + 'px');
}
}
},
/**
* Reset sticky portlet positions
*/
resetSticky: function() {
if (!the.head) {
return;
}
if (mUtil.hasClass(body, 'm-portlet--sticky') === false) {
mUtil.css(the.head, 'z-index', '');
mUtil.css(the.head, 'top', '');
mUtil.css(the.head, 'left', '');
mUtil.css(the.head, 'right', '');
}
},
/**
* Destroy sticky portlet
*/
destroySticky: function() {
if (!the.head) {
return;
}
Plugin.resetSticky();
window.removeEventListener('scroll', Plugin.onScrollSticky);
},
/**
* Remove portlet
*/
remove: function() {
if (Plugin.eventTrigger('beforeRemove') === false) {
return;
}
if (mUtil.hasClass(body, 'm-portlet--fullscreen') && mUtil.hasClass(element, 'm-portlet--fullscreen')) {
Plugin.fullscreen('off');
}
Plugin.removeTooltips();
mUtil.remove(element);
Plugin.eventTrigger('afterRemove');
},
/**
* Set content
*/
setContent: function(html) {
if (html) {
the.body.innerHTML = html;
}
},
/**
* Get body
*/
getBody: function() {
return the.body;
},
/**
* Get self
*/
getSelf: function() {
return element;
},
/**
* Setup tooltips
*/
setupTooltips: function() {
if (the.options.tooltips) {
var collapsed = mUtil.hasClass(element, 'm-portlet--collapse') || mUtil.hasClass(element, 'm-portlet--collapsed');
var fullscreenOn = mUtil.hasClass(body, 'm-portlet--fullscreen') && mUtil.hasClass(element, 'm-portlet--fullscreen');
//== Remove
var remove = mUtil.find(the.head, '[m-portlet-tool=remove]');
if (remove) {
var placement = (fullscreenOn ? 'bottom' : 'top');
var tip = new Tooltip(remove, {
title: the.options.tools.remove,
placement: placement,
offset: (fullscreenOn ? '0,10px,0,0' : '0,5px'),
trigger: 'hover',
template: '
\
\
\
'
});
mUtil.data(remove).set('tooltip', tip);
}
//== Reload
var reload = mUtil.find(the.head, '[m-portlet-tool=reload]');
if (reload) {
var placement = (fullscreenOn ? 'bottom' : 'top');
var tip = new Tooltip(reload, {
title: the.options.tools.reload,
placement: placement,
offset: (fullscreenOn ? '0,10px,0,0' : '0,5px'),
trigger: 'hover',
template: '
\
\
\
'
});
mUtil.data(reload).set('tooltip', tip);
}
//== Toggle
var toggle = mUtil.find(the.head, '[m-portlet-tool=toggle]');
if (toggle) {
var placement = (fullscreenOn ? 'bottom' : 'top');
var tip = new Tooltip(toggle, {
title: (collapsed ? the.options.tools.toggle.expand : the.options.tools.toggle.collapse),
placement: placement,
offset: (fullscreenOn ? '0,10px,0,0' : '0,5px'),
trigger: 'hover',
template: '
\
\
\
'
});
mUtil.data(toggle).set('tooltip', tip);
}
//== Fullscreen
var fullscreen = mUtil.find(the.head, '[m-portlet-tool=fullscreen]');
if (fullscreen) {
var placement = (fullscreenOn ? 'bottom' : 'top');
var tip = new Tooltip(fullscreen, {
title: (fullscreenOn ? the.options.tools.fullscreen.off : the.options.tools.fullscreen.on),
placement: placement,
offset: (fullscreenOn ? '0,10px,0,0' : '0,5px'),
trigger: 'hover',
template: '